#!/usr/bin/env python3
"""
航母态势对象数据导入脚本
从 Excel 文件读取航母数据并导入到 PostgreSQL 数据库
"""

import sys
import os
import logging
import asyncio
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, List
import re

# 尝试导入 pandas 和 openpyxl
try:
    import pandas as pd
    HAS_PANDAS = True
except ImportError:
    HAS_PANDAS = False
    logging.warning("pandas 未安装，将尝试使用其他方式读取Excel文件")

try:
    import openpyxl
    HAS_OPENPYXL = True
except ImportError:
    HAS_OPENPYXL = False
    logging.warning("openpyxl 未安装，将尝试使用其他方式读取Excel文件")

# 添加项目根目录到 Python 路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

# 直接导入所需模块
import src.situation.database
import src.situation.models
import src.situation.service
import src.situation.schemas

from src.situation.database import get_db_session, engine, Base
from src.situation.models import SituationObject
from src.situation.service import SituationService
from src.situation.schemas import SituationObjectCreate, DeploymentStatus, ObjectType


# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('logs/aircraft_carrier_import.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)


def read_excel_file(file_path: str) -> List[Dict[str, Any]]:
    """
    读取 Excel 文件并返回数据列表

    Args:
        file_path: Excel 文件路径

    Returns:
        包含航母数据的字典列表
    """
    try:
        if HAS_PANDAS and HAS_OPENPYXL:
            # 使用 pandas 读取 Excel 文件
            df = pd.read_excel(file_path)
            logger.info(f"使用 pandas 成功读取 Excel 文件，共 {len(df)} 行数据")

            # 转换为字典列表
            data = df.to_dict('records')

            # 记录列名
            logger.info(f"Excel 文件包含的列: {list(df.columns)}")

            return data
        else:
            # 使用 openpyxl 直接读取
            if not HAS_OPENPYXL:
                raise ImportError("需要安装 pandas 和 openpyxl 来读取 Excel 文件")

            from openpyxl import load_workbook

            wb = load_workbook(filename=file_path, read_only=True)
            sheet = wb.active

            # 读取标题行
            headers = [cell.value for cell in next(sheet.iter_rows(min_row=1, max_row=1))]
            logger.info(f"Excel 文件包含的列: {headers}")

            # 读取数据行
            data = []
            for row in sheet.iter_rows(min_row=2, values_only=True):
                if any(row):  # 跳过空行
                    row_dict = {headers[i]: row[i] for i in range(len(headers)) if i < len(row)}
                    data.append(row_dict)

            wb.close()
            logger.info(f"使用 openpyxl 成功读取 Excel 文件，共 {len(data)} 行数据")
            return data

    except Exception as e:
        logger.error(f"读取 Excel 文件失败: {e}")
        if not HAS_PANDAS or not HAS_OPENPYXL:
            logger.error("请安装必要的依赖: uv add pandas openpyxl")
        raise


def parse_float_field(field_value: Any) -> float:
    """
    解析浮点数字段

    Args:
        field_value: 字段值

    Returns:
        浮点数或 None
    """
    if field_value is None or field_value == '':
        return None

    try:
        if isinstance(field_value, (int, float)):
            return float(field_value)

        if isinstance(field_value, str):
            # 移除可能的单位和其他字符
            # 提取数字部分（包括小数点、负号和逗号）
            cleaned = field_value.replace(',', '').replace('，', '')
            numbers = re.findall(r'-?\d+\.?\d*', cleaned)
            if numbers:
                # 如果有多个数字，取第一个
                return float(numbers[0])

            logger.warning(f"字符串中未找到有效数字: {field_value}")
            return None

    except (ValueError, TypeError) as e:
        logger.warning(f"无法解析浮点数: {field_value}, 错误: {e}")
        return None

    return None


def parse_list_field(field_value: Any) -> List[str]:
    """
    解析列表字段

    Args:
        field_value: 字段值

    Returns:
        字符串列表
    """
    if field_value is None:
        return []

    if isinstance(field_value, list):
        return [str(item).strip() for item in field_value if item]

    if isinstance(field_value, str):
        # 尝试按分隔符分割
        separators = [',', '，', ';', '；', '|', '、']
        for sep in separators:
            if sep in field_value:
                return [item.strip() for item in field_value.split(sep) if item.strip()]

        # 如果没有分隔符，作为单个元素
        return [field_value.strip()] if field_value.strip() else []

    return [str(field_value)]


def convert_to_situation_object(carrier_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    将航母数据转换为态势对象格式

    Args:
        carrier_data: 航母原始数据

    Returns:
        符合态势对象模型的数据字典
    """
    try:
        # 基础信息映射
        name = carrier_data.get('名称') or carrier_data.get('name')
        code = carrier_data.get('编码') or carrier_data.get('code')

        # 如果没有编码，使用名称生成编码
        if not code and name:
            # 提取英文部分作为编码，或使用拼音首字母
            english_part = re.search(r'[A-Za-z]+', name)
            if english_part:
                code = f"CV-{english_part.group(0).upper()}"
            else:
                # 使用时间戳生成唯一编码
                import random
                code = f"CV-{datetime.now().strftime('%Y%m%d%H%M%S')}-{random.randint(1000, 9999)}"

        # 如果没有名称，使用编码作为名称
        if not name and code:
            name = f"航母-{code}"
        elif not name and not code:
            # 如果都没有，生成一个默认名称
            name = f"未知航母-{datetime.now().strftime('%Y%m%d%H%M%S')}"
            code = f"CV-{datetime.now().strftime('%Y%m%d%H%M%S')}"

        # 解析排水量
        displacement_raw = carrier_data.get('排水量') or carrier_data.get('displacement')
        displacement = parse_float_field(displacement_raw)

        # 解析最大里程（续航力）
        endurance_raw = carrier_data.get('最大里程') or carrier_data.get('endurance')
        endurance = parse_float_field(endurance_raw)

        # 解析最高速度
        max_speed_raw = carrier_data.get('最高速度') or carrier_data.get('max_speed')
        max_speed = parse_float_field(max_speed_raw)

        # 动力系统
        propulsion_type = carrier_data.get('动力系统') or carrier_data.get('propulsion_type') or ''

        # 最大载机数量（注意：Excel中这个字段名实际对应的是武器系统，需要调整）
        # 从Excel数据分析，"最大载机数量"列实际存储的是武器系统信息
        # 而"飞行甲板"列存储的是载机数量信息
        armament_raw = carrier_data.get('最大载机数量') or carrier_data.get('armament') or ''
        flight_deck_raw = carrier_data.get('飞行甲板') or carrier_data.get('flight_deck') or carrier_data.get('aircraft_capacity') or ''

        # 从飞行甲板信息中提取载机数量
        aircraft_capacity = parse_float_field(flight_deck_raw)
        if aircraft_capacity is None and flight_deck_raw:
            # 如果无法解析为数字，保留原始文本
            aircraft_capacity_text = str(flight_deck_raw)
        else:
            aircraft_capacity_text = f"{int(aircraft_capacity)}架" if aircraft_capacity else flight_deck_raw

        # 处理生产日期和服役时间
        production_date = carrier_data.get('生产日期') or carrier_data.get('production_date') or ''
        service_time = carrier_data.get('服役时间') or carrier_data.get('service_time') or ''

        # 提取建造年份
        construction_year = None
        if production_date:
            year_match = re.search(r'(\d{4})', str(production_date))
            if year_match:
                construction_year = int(year_match.group(1))

        # 构建态势对象数据
        situation_data = {
            'object_type': ObjectType.SEA_TARGET,  # 航母属于海上目标
            'name': name,
            'code': code,
            'deployment_status': DeploymentStatus.DEPLOYED,  # 默认为已部署

            # 海上目标特定数据存储在 type_specific_data 中
            'type_specific_data': {
                'target_category': '航母',  # 直接使用航母作为类别

                # 基本参数
                'displacement': displacement,  # 排水量(吨)
                'max_speed': max_speed,  # 最大航速(节)
                'endurance': endurance,  # 续航力
                'propulsion_type': propulsion_type,  # 推进系统类型

                # 航母特有字段
                'aircraft_capacity': aircraft_capacity,  # 最大载机数量
                'aircraft_capacity_text': aircraft_capacity_text,  # 载机数量描述
                'flight_deck_info': str(flight_deck_raw),  # 飞行甲板信息

                # 武器系统
                'armament_text': str(armament_raw),  # 武器系统文本描述

                # 建造信息
                'construction_year': construction_year,  # 建造年份
                'production_date': str(production_date),  # 生产日期
                'service_time': str(service_time),  # 服役时间
            },

            # 适用场景
            'applicable_scenarios': ['海上作战', '远洋部署', '舰载航空作战', '海上威慑'],

            # 标签
            'tags': ['航母', '海上目标', '海军装备', '战略武器'],

            # 其他元数据
            'extra_metadata': {
                'data_source': 'excel_import',
                'import_time': datetime.now().isoformat(),
                'production_date': str(production_date),
                'service_time': str(service_time),
            },

            # 审计信息
            'created_by': 'aircraft_carrier_import_script',
            'updated_by': 'aircraft_carrier_import_script'
        }

        logger.debug(f"成功转换航母数据: {name} (编码: {code})")
        return situation_data

    except Exception as e:
        logger.error(f"转换航母数据失败: {e}")
        logger.error(f"原始数据: {carrier_data}")
        raise


async def import_aircraft_carrier_data(excel_file_path: str, batch_size: int = 10):
    """
    导入航母数据到数据库

    Args:
        excel_file_path: Excel 文件路径
        batch_size: 批量处理大小
    """
    logger.info(f"=" * 80)
    logger.info(f"开始导入航母数据")
    logger.info(f"文件路径: {excel_file_path}")
    logger.info(f"=" * 80)

    try:
        # 读取 Excel 文件
        carrier_data_list = read_excel_file(excel_file_path)
        logger.info(f"成功读取 Excel 文件，共 {len(carrier_data_list)} 条航母数据")

        # 首先初始化数据库（确保表结构正确）
        logger.info("正在初始化数据库...")
        from src.situation.database import init_db
        await init_db()
        logger.info("数据库初始化完成")

        # 创建数据库会话
        async for db in get_db_session():
            success_count = 0
            error_count = 0
            skipped_count = 0
            error_details = []

            for i, carrier_data in enumerate(carrier_data_list, 1):
                try:
                    logger.info(f"\n{'=' * 60}")
                    logger.info(f"处理第 {i}/{len(carrier_data_list)} 条数据")

                    # 转换为态势对象格式
                    situation_data = convert_to_situation_object(carrier_data)

                    logger.info(f"航母名称: {situation_data['name']}")
                    logger.info(f"航母编码: {situation_data.get('code', '无')}")

                    # 创建态势对象
                    obj_create = SituationObjectCreate(**situation_data)

                    # 创建态势对象 (SituationService.create_object 已经内置了编码重复检查)
                    created_object = await SituationService.create_object(
                        db, obj_create, user="aircraft_carrier_import_script"
                    )
                    logger.info(f"✓ 成功创建态势对象: {created_object.name} (ID: {created_object.id})")
                    success_count += 1

                except ValueError as e:
                    error_msg = str(e)
                    if "已存在" in error_msg or "重复" in error_msg:
                        logger.warning(f"✗ 数据已存在，跳过: {error_msg}")
                        skipped_count += 1
                        error_details.append({
                            'index': i,
                            'name': carrier_data.get('名称', '未知'),
                            'reason': '数据已存在',
                            'error': error_msg
                        })
                    else:
                        logger.error(f"✗ 数据验证错误: {error_msg}")
                        error_count += 1
                        error_details.append({
                            'index': i,
                            'name': carrier_data.get('名称', '未知'),
                            'reason': '数据验证失败',
                            'error': error_msg
                        })
                except Exception as e:
                    logger.error(f"✗ 处理第 {i} 条数据失败: {e}")
                    error_count += 1
                    error_details.append({
                        'index': i,
                        'name': carrier_data.get('名称', '未知'),
                        'reason': '处理失败',
                        'error': str(e)
                    })
                    continue

            # 输出导入摘要
            logger.info(f"\n{'=' * 80}")
            logger.info("导入完成！")
            logger.info(f"{'=' * 80}")
            logger.info(f"总计: {len(carrier_data_list)} 条")
            logger.info(f"成功: {success_count} 条")
            logger.info(f"跳过: {skipped_count} 条（已存在）")
            logger.info(f"失败: {error_count} 条")
            logger.info(f"{'=' * 80}")

            # 如果有错误，输出错误详情
            if error_details:
                logger.info("\n错误详情：")
                for detail in error_details:
                    logger.info(f"  第 {detail['index']} 条 - {detail['name']}: {detail['reason']}")
                    logger.debug(f"    错误信息: {detail['error']}")

            return {
                'total': len(carrier_data_list),
                'success': success_count,
                'skipped': skipped_count,
                'error': error_count,
                'error_details': error_details
            }

    except Exception as e:
        logger.error(f"导入过程中发生严重错误: {e}")
        import traceback
        logger.error(traceback.format_exc())
        raise


async def main():
    """主函数"""
    # 默认文件路径
    default_file = "test/data-situation/aircraft.xlsx"

    # 检查命令行参数
    if len(sys.argv) > 1:
        excel_file = sys.argv[1]
    else:
        excel_file = default_file

    # 检查文件是否存在
    if not os.path.exists(excel_file):
        logger.error(f"文件不存在: {excel_file}")
        logger.info("用法: python scripts/import_aircraft_carrier_data.py [excel_file_path]")
        sys.exit(1)

    try:
        # 确保日志目录存在
        os.makedirs("logs", exist_ok=True)

        # 导入数据
        await import_aircraft_carrier_data(excel_file)

        logger.info("航母数据导入成功完成！")

    except Exception as e:
        logger.error(f"导入失败: {e}")
        sys.exit(1)


def run_main():
    """运行主函数的同步包装器"""
    asyncio.run(main())


if __name__ == "__main__":
    run_main()
